package com.bsoft.service.impl;

import com.bsoft.Exception.CommonException;
import com.bsoft.aop.annotation.MultiDataSourceTransactional;
import com.bsoft.mapper.business.RegisterMapper;
import com.bsoft.mapper.identity.IdentityMapper;
import com.bsoft.service.RegisterService;

import com.bsoft.utils.ConmonUtil;
import com.bsoft.utils.HttpClientUtil;
import com.bsoft.utils.JSONUtil;
import com.bsoft.utils.WebserviceClient;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;


import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.sql.rowset.serial.SerialBlob;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.sql.Blob;
import java.sql.Clob;
import java.util.*;

/**
 * 挂号实现类
 *
 * @author liujx
 * @date 2019/7/2
 */
@Service
@EnableTransactionManagement
public class RegisterServiceImpl extends ConmonUtil implements RegisterService {

    private static Logger logger = LoggerFactory.getLogger(RegisterServiceImpl.class);

    @Resource
    private RegisterMapper registerMapper;

    @Resource
    private IdentityMapper identityMapper;

    @Value("${aa}")
    private String aa;

    @Value("${aggregatePayUrl}")
    private String aggregatePayUrl;

    /**
     * create by: hxy
     * description: 查询科室
     * create time: 2019/03/15 14:56
     *
     * @return a
     * @Param: null
     */
    @Override
    public String listDepartment(Map<String, Object> req) throws CommonException {
        //判断必填项是否为空
        isNUll(req, "hospitalId");
        //分页判断
//        pagination(req);
        List<Map<String, Object>> department = registerMapper.listDepartment(req);
        return getSuccessPagination(department);
    }

    @Override
    public String getBrdaList(Map<String, Object> req) {
        List<Map<String, Object>> brdaInfoList = registerMapper.getBrdaList(req);
        Map<String, Object> map = brdaInfoList.get(0);
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            if (entry.getValue() instanceof Clob) {
                entry.setValue(ClobToString((Clob) entry.getValue()));
            }
        }
//        Long jlxh = registerMapper.getIPrimaryKey("seq_MS_FKXX");
        return getSuccessTest(brdaInfoList.get(0));
    }

    @Override
    public String getBrdaGHMX(Map<String, Object> req) {
        /*// 使用getOrDefault以防键不存在  // 过滤掉null值（如果键不存在）
        //k aa v 11
        List<Object> sfzhList = Stream.of(req.getOrDefault("sfzhList", null))
                .filter(obj -> obj != null).collect(Collectors.toList());
        //k aa v 11,22 .peek 在流操作每一个元素在单独增加一个操作 切不影响流
        List<String> sfzhList1 = Arrays.stream(req.getOrDefault("sfzhList", "").toString().split(","))
                .map(s -> {
                    System.out.println("在处理前的原字符串:" + s);
                    String res = s.trim().toUpperCase();
                    System.out.println("在处理后的原字符串:" + res);
                    return res;
                })
                .collect(Collectors.toList());


        req.put("sfzhList", sfzhList1);

        List<Map<String, Object>> getBrdaGHMXList = registerMapper.getBrdaGHMX(req);

        //List 转 Stream[List.Stream()] , array 转Stream[ arrays.Stream()]
        //1.过滤流中的元素。 filter
        getBrdaGHMXList.stream().forEach(s -> {
            List<Map<String, Object>> ghmxList = (List<Map<String, Object>>) s.get("ghmxList");
            List<Map<String, Object>> collect = ghmxList.stream().filter(v -> !v.get("JZHM").toString().contains("Auto")).collect(Collectors.toList());
            s.put("ghmxList", collect);
        });*/

        Map<String, Object> aa = new HashMap<>();
        aa.put("JGID", "1");
        aa.put("GLXH", "2");
        aa.put("PJZT", "3");
        aa.put("HPDM", "11111");
        aa.put("HPHM", "213331");
        aa.put("HPJYM", "其味无穷财务区分");
        aa.put("HPYM", "12324");
        aa.put("HPWWYM", "请问定位器放弃过去");
        aa.put("DZPJTP", "其味无穷恶妇去污粉");
        return getSuccessTest(aa);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String say(Map<String, Object> req) throws Exception {

        int a = registerMapper.updateBrdaXM(req);

//        RegisterService bean = SpringBeanUtil.getBean(RegisterService.class);

        ((RegisterService) AopContext.currentProxy()).updateBRDA(req);
        if (1 == 1) {
            throw new CommonException("更新失败了");
        }

        return "欢迎您!";
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    @Transactional(value = "hisTransactionManager", rollbackFor = Exception.class)
    public String updateBRDA(Map<String, Object> req) {
        int a = registerMapper.updateBrda(req);
        if (1 == 1) {
            throw new CommonException("更新失败");
        }
        return getSuccess("更新成功!!");
    }

    @Override
    @MultiDataSourceTransactional(transactionManagers = {"hisTransactionManager", "portalTransactionManager"})
    public String testTransactionManager(Map<String, Object> req) {


        Long identity = getIdentity("ms", "MS_BANK_LOG");

        String brid = req.get("BRID").toString();

        //更新portal库gy_brda
        int i = identityMapper.updateGY_BRDA(req);

        //更新his库ms_brda
        i = registerMapper.updateBrda(req);

        if (true) {
            throw new CommonException("操作异常了请查看事务是否能够回滚");
        }

        return "操作成功";
    }

    /**
     * 住院医保电子票据开票: 涉及医保  参数不全或参数格式错误：numberOfSettlement
     */
    @Override
    public String openHospitalTicket_YB(Map<String, Object> req) {
        isNUll(req, "FPHM");

        String bb = aa;
        //先看这张发票是否有医保数据
        String fphm = req.get("FPHM").toString();
        boolean ybLog = false;
        String type = "2";
        Map<String, Object> ybInfoMap = registerMapper.getYB_FPHM(fphm);
        if (ybInfoMap != null && !ybInfoMap.isEmpty()) {
            ybLog = true;
            type = "1";
        }/*else {
            throw new CommonException("该接口只支持涉及医保的出院结算开单子发票,如涉及纯自费结算请走[openHospitalTicket]开票!");
        }*/

        //组装电子票据的参数          select * from V_DZFPSC_ZYJS where rownum &lt;= 500
        List<Map<String, Object>> hospitalList = registerMapper.InvEBillHospitalized(fphm);

        String resultString = "";
        //type 1 医保 2 自费
        for (Map<String, Object> map : hospitalList) {
            map.put("type", type);
            List<Map<String, Object>> payChannelDetailList = new ArrayList<>();
            List<Map<String, Object>> chargeDetailList = new ArrayList<>();
            List<Map<String, Object>> listDetailList = new ArrayList<>();
            List<Map<String, Object>> otherInfoList = new ArrayList<>();
            List<Map<String, Object>> payMentVoucherList = new ArrayList<>();
            List<Map<String, Object>> otherMedicalList = new ArrayList<>();
            List<Map<String, Object>> emptyList = new ArrayList<>();

            //交费渠道列表  select * from v_payChannelDetail_zy where MZXH =#{MZXH}
            payChannelDetailList = registerMapper.getPayChannelDetailList_zy(map);
            //收费项目明细  select ROW_NUMBER() OVER(ORDER BY SYSTIMESTAMP)  as "sortNo",a.* from v_chargeDetail_zy a where mzxh =#{MZXH}
            chargeDetailList = registerMapper.getChargeDetailList_zy_yb(map);
            //清单项目明细  select ROW_NUMBER() OVER(ORDER BY SYSTIMESTAMP)  as "sortNo",a.* from v_listDetail_zy a where mzxh =#{MZXH}
            listDetailList = registerMapper.getListDetailList_zy_yb(map);
            //其它扩展信息列表 select  top 500 * from dbo.v_otherInfoList_zy where "invoiceNumber" =#{invoiceNumber}
            otherInfoList = registerMapper.getOtherInfoList_zy(map);

            map.put("payChannelDetail", payChannelDetailList);//交费渠道列表
            map.put("chargeDetail", chargeDetailList);// 收费项目明细
            map.put("listDetail", listDetailList);//清单项目明细
            map.put("otherInfo", otherInfoList);//其它扩展信息列表
            map.put("otherMedicalList", emptyList);//其它支付信息列表
            map.put("payOrderInfo", emptyList);//其它医保信息列表
            map.put("payMentVoucher", payMentVoucherList);//预交金凭证消费扣款列表
            String map2Json = JSONUtil.map2Json(map);
            logger.error("住院电子发票[医保]:上传数据:" + map2Json);
            resultString = HttpClientUtil.doPostJsonPj("http://196.168.0.168:8900/BS-EI-FrameWork/electronic/invEBillHospitalizedAll", map2Json, "1");
            logger.error("住院电子发票[医保]:返回数据:" + resultString);
        }

        return resultString;
    }

    /**
     * 住院医保电子票据开票 : 出自费结算
     */
    @Override
    public String openHospitalTicket(Map<String, Object> req) {
        isNUll(req, "FPHM");

        //先看这张发票是否有医保数据
        String fphm = req.get("FPHM").toString();
        boolean ybLog = false;
        String type = "2";
        Map<String, Object> ybInfoMap = registerMapper.getYB_FPHM(fphm);
        if (ybInfoMap != null || !ybInfoMap.isEmpty()) {
            throw new CommonException("该接口只支持纯自费出院结算开单子发票,如涉及医保结算请走[openHospitalTicket_YB]开票!");
        }
        //组装电子票据的参数          select * from V_DZFPSC_ZYJS where rownum &lt;= 500
        List<Map<String, Object>> hospitalList = registerMapper.InvEBillHospitalized(fphm);

        String resultString = "";
        //type 1 医保 2 自费
        for (Map<String, Object> map : hospitalList) {
            map.put("type", type);
            List<Map<String, Object>> payChannelDetailList = new ArrayList<>();
            List<Map<String, Object>> chargeDetailList = new ArrayList<>();
            List<Map<String, Object>> listDetailList = new ArrayList<>();
            List<Map<String, Object>> otherInfoList = new ArrayList<>();
            List<Map<String, Object>> payMentVoucherList = new ArrayList<>();
            List<Map<String, Object>> emptyList = new ArrayList<>();

            //交费渠道列表  select * from v_payChannelDetail_zy where MZXH =#{MZXH}
            payChannelDetailList = registerMapper.getPayChannelDetailList_zy(map);
            //收费项目明细  select ROW_NUMBER() OVER(ORDER BY SYSTIMESTAMP)  as "sortNo",a.* from v_chargeDetail_zy a where mzxh =#{MZXH}
            chargeDetailList = registerMapper.getChargeDetailList_zy(map);
            //清单项目明细  select ROW_NUMBER() OVER(ORDER BY SYSTIMESTAMP)  as "sortNo",a.* from v_listDetail_zy a where mzxh =#{MZXH}
            listDetailList = registerMapper.getListDetailList_zy(map);
            //其它扩展信息列表 select  top 500 * from dbo.v_otherInfoList_zy where "invoiceNumber" =#{invoiceNumber}
            otherInfoList = registerMapper.getOtherInfoList_zy(map);


            map.put("payChannelDetail", payChannelDetailList);//交费渠道列表
            map.put("chargeDetail", chargeDetailList);// 收费项目明细
            map.put("listDetail", listDetailList);//清单项目明细
            map.put("otherInfo", otherInfoList);//其它扩展信息列表
            map.put("otherMedicalList", emptyList);//其它支付信息列表
            map.put("payOrderInfo", emptyList);//其它医保信息列表
            map.put("payMentVoucher", payMentVoucherList);//预交金凭证消费扣款列表
            String map2Json = JSONUtil.map2Json(map);
            logger.error("住院电子发票[纯自费]:上传数据:" + map2Json);
            resultString = HttpClientUtil.doPostJsonPj("http://192.168.200.201:8900/BS-EI-FrameWork/electronic/invEBillHospitalizedAll", map2Json, "1");
            logger.error("住院电子发票[纯自费]:返回数据:" + resultString);
        }


        return resultString;
    }

    @Override
    public String storedProceduresTest(Map<String, Object> wz_map) {

        String cjxh_wz = "";
        Map<Object, Object> wz_stock_Check_Map = new HashMap<>();
        wz_stock_Check_Map.put("al_kfxh", 1);//当前库房
        wz_stock_Check_Map.put("al_wzxh", 1);//物资序号
        wz_stock_Check_Map.put("al_cjxh", 1);//厂家序号
        wz_stock_Check_Map.put("al_zxks", 1);//执行科室
        wz_stock_Check_Map.put("adc_wzdj", 1);//物资单价
        wz_stock_Check_Map.put("al_bcsysl", 1);//本次使用数量
        wz_stock_Check_Map.put("al_zyh", 1);//就诊序号

//        wz_stock_Check_Map.put("at_mzpcjlxh",wz_map.get("al_kfxh"));//当前库房
//        wz_stock_Check_Map.put("at_zypcjlxh",wz_map.get("al_wzxh"));//物资序号
//        wz_stock_Check_Map.put("at_smpcjlxh",wz_map.get("al_cjxh"));//厂家序号
//        wz_stock_Check_Map.put("at_yjpcjlxh", wz_map.get("al_zxks"));//执行科室

        wz_stock_Check_Map.put("v_IDENTITY", "GY_IDENTITY_MS");//物资单价
        wz_stock_Check_Map.put("v_tablename", "MS_BRDA");//本次使用数量
        wz_stock_Check_Map.put("v_count", 1);//就诊序号

        registerMapper.getMax(wz_stock_Check_Map);
        registerMapper.wz_check_StoredProcedure(wz_stock_Check_Map);
        if (!(wz_stock_Check_Map.get("al_result") == null || wz_stock_Check_Map.get("as_error").toString().equals(""))) {
            throw new CommonException(wz_stock_Check_Map.get("prm_errorMsg").toString());
        }
        if ("0".equals(wz_stock_Check_Map.get("al_result").toString())) {
            cjxh_wz = wz_map.get("CJXH").toString();
        }

        return cjxh_wz;
    }


    public List<Map<String, Object>> findAllPatients() {
        // 模拟数据库中的患者列表
        List<Map<String, Object>> patientsList = new ArrayList<>();
        Map<String, Object> aa = new HashMap<>();
        aa.put("张三", "11");
        Map<String, Object> bb = new HashMap<>();
        bb.put("李四", "22");
        patientsList.add(aa);
        patientsList.add(bb);
        return patientsList;
    }

    /**
     * HIHIS大区版聚合支付二维码获取
     */
    @Override
    public void getSbCompanyPay(String idVismed, String acToken,HttpServletResponse response) throws Exception {
        Assert.hasText(idVismed, "idVismed不能为空");
        Map<String, Object> qrCodeParmMap = registerMapper.getQrCodeParm(idVismed);
        Assert.notEmpty(qrCodeParmMap, "根据入参idVismed[" + idVismed + "::V_HIHIS_qrCodePay]获取二维码参数失败");

        Map<String, Object> busInfoMap = new HashMap<>();
        busInfoMap.put("idCard", qrCodeParmMap.get("idCard"));
        busInfoMap.put("medicalCardId", qrCodeParmMap.get("medicalCardId"));
        busInfoMap.put("operatorId", qrCodeParmMap.get("operatorId"));
        busInfoMap.put("id_vismed", qrCodeParmMap.get("idVismed"));

        //if(ObjectUtils.isEmpty(qrCodeParmMap.get("idCard"))) throw  new CommonException("businfo中的idCard不能为空");

        String busInfoStr = JSONUtil.map2Json(busInfoMap);
        qrCodeParmMap.put("busInfo", busInfoStr);

        String qrCodeJson = JSONUtil.map2Json(qrCodeParmMap);
        logger.info("调用:聚合支付[qrCodePay]请求参数::" + qrCodeJson);
        String s = WebserviceClient.webServiceInvoker(qrCodeJson, "qrCodePay", aggregatePayUrl);
        logger.info("调用:聚合支付[qrCodePay]返回结果::" + s);
        if (StringUtils.isNotBlank(s)) {
            Map<String, Object> resMap = JSONUtil.toHashMap(s);
            if (StringUtils.equals("SUCCESS", resMap.get("return_code").toString())) {
                String url = resMap.get("url").toString();
                createImage(url,response);
            }
        }
    }

    /**
     * 生成支付二维码
     * @param paymentUrl 支付地址（如：alipay://... 或 weixin://...）
     * @param width 图片宽度
     * @param height 图片高度
     * @param filePath 输出文件路径
     */
    public  void createImage(String url, HttpServletResponse response) throws Exception {


        //根据获取到的二维码
        Map map = new HashMap();
        //纠错程度
        map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        //字符编码
        map.put(EncodeHintType.CHARACTER_SET, "utf-8");
        //边距
        map.put(EncodeHintType.MARGIN, 1);

        BitMatrix matrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 300, 300, map);

        int width = matrix.getWidth();
        int height = matrix.getHeight();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// RGB 黑白模型，颜色参数

        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        response.setContentType("image/png");
        ServletOutputStream os = response.getOutputStream();
        if (image != null) {
            ImageIO.write(image, "png", os);
        }
    }

    //获取二维码图片
    public String getImageMeth(String imageUrl) {
        String qrCodeUrl = imageUrl;
        String base64String = "";
        try {
            // 1. 下载图片
            byte[] imageBytes = downloadImage(qrCodeUrl);

            // 2. 转换为 Base64 字符串
           /* base64String = bytesToBase64(imageBytes);
            logger.info("图片转换为Base64字符串成功{}",base64String);*/

            // 3. 转换为十六进制字符串（可选）
            //base64String = bytesToHex(imageBytes);
            //logger.info("图片转换为十六进制字符串成功{}" , base64String);

            base64String = bytesToBinaryString(imageBytes);
            logger.info("图片转换为二进制字符串成功{}" , base64String);
            return base64String;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "FAIL";
    }

    // 下载图片并返回字节数组
    private static byte[] downloadImage(String imageUrl) throws Exception {
        URL url = new URL(imageUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");

        try (InputStream inputStream = connection.getInputStream();
             ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
            byte[] data = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(data)) != -1) {
                buffer.write(data, 0, bytesRead);
            }
            return buffer.toByteArray();
        }
    }

    //base加密
    private static String bytesToBase64(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    //转为十六进制字符串
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            hexString.append(String.format("%02X", b));
        }
        return hexString.toString();
    }

    // 将字节数组转换为二进制字符串（每个字节转换为8位二进制）
    private static String bytesToBinaryString(byte[] bytes) {
        StringBuilder binaryString = new StringBuilder();
        for (byte b : bytes) {
            // 将字节转换为8位二进制字符串，补足前导零
            String binary = String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
            binaryString.append(binary);
        }
        return binaryString.toString();
    }
    /**
     * 手动编写事务代码如下：
     * 注意使用事务一定要是public的方法
     *
     * @return 是否执行成功
     */
    /*@Override
    @Transactional(rollbackFor = Exception.class)
    public String updateBRDA(Map<String, Object> req) {
        // 尽量要把select放到事务外面，因为查询不牵扯到事务
        List<Map<String, Object>> brdaInfoList = registerMapper.getBrdaList(req);

        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        // 定义该事务的名称、事务级别
        def.setName("upDaTransaction");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 记录事务执行之前的状态
        TransactionStatus status = regTransactionManager.getTransaction(def);
        // 此处设定的是sql语句出错，所以使用try catch包围，也可以根据实际的业务确定执行还是回滚
        try {
            // 执行操作
            brdaInfoList.get(0).put("phoneNum",req.get("phoneNum"));
            int a = registerMapper.updateBrda(brdaInfoList.get(0));
            // 如果没有出错，提交该事务
            regTransactionManager.commit(status);
        } catch (Exception e) {
            // 错误输入改成日志
            System.err.println(e.getMessage());
            // 如果发送错误回滚该事物
            regTransactionManager.rollback(status);
            return getSuccessFull("更新档案("+brdaInfoList.get(0).get("BRID")+")失败!!");
        }
        return getSuccess("更新成功!!");
    }*/
   /* @Override
    @Transactional(rollbackFor = Exception.class)
    public String updateBRDA(Map<String, Object> req) {
        int a = registerMapper.updateBrda(req);
        if (a == 0) {
            throw new CommonException("更新失败!");
        }

        TransactionSynchronizationManager.bindResource("req", req);
        // 在事务提交后发送邮件
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                Map<String, Object> aa = (Map<String, Object>) TransactionSynchronizationManager.getResource("req");
                aa.put("phoneNum","aaa");
                aa.put("patientId","11");
                String s1 = JSONUtil.map2Json(aa);
                String s = HttpClientUtil.doPostJson("http://127.0.0.1:8089/bsoft/register/patientIsMatch", s1);
                System.out.println("返回结果::"+s);
            }
        });


        if (1!=0){
            throw new CommonException("更新失败!");
        }

        return getSuccess("更新成功!!");
    }*/


}
